package com.net.xpay.common.service.impl;

import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipayFundAccountbookNotifySubscribeResponse;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.net.xpay.common.constant.GenIdPrefixConstant;
import com.net.xpay.common.domain.SafePayBookPreApplyRecord;
import com.net.xpay.common.domain.SafePayBusinessAuthAuditRecord;
import com.net.xpay.common.domain.User;
import com.net.xpay.common.domain.UserShard;
import com.net.xpay.common.manager.SafePayBookPreApplyRecordManager;
import com.net.xpay.common.manager.SafePayBusinessAuthAuditRecordManager;
import com.net.xpay.common.manager.UserManager;
import com.net.xpay.common.manager.UserShardManager;
import com.net.xpay.common.model.SafePayBookPreApplyModel;
import com.net.xpay.core.constant.PoseidonErrorCode;
import com.net.xpay.core.domain.safePay.SafePayBookAccount;
import com.net.xpay.core.enums.SafePayBookAccountAuditStatus;
import com.net.xpay.core.enums.SafePayBookAccountBookStatus;
import com.net.xpay.core.enums.SafePayBookAccountSignMethod;
import com.net.xpay.core.enums.SafePayBookAccountSignStatus;
import com.net.xpay.core.manager.safePay.SafePayBookAccountManager;
import com.net.xpay.core.utils.GenIdUtil;
import com.net.xpay.core.utils.UuidUtil;
import com.net.common.concurrent.ThreadUtil;
import com.net.common.exception.BusinessException;
import com.net.common.util.LocalDateUtil;
import com.net.xpay.alipay.enums.IdentityType;
import com.net.xpay.alipay.model.AlipayFundAccountbookPageCreateModel;
import com.net.xpay.alipay.safePay.PoseidonSafePayAlipayClient;
import com.net.xpay.common.service.SafePayBookPreApplyService;
import com.net.shard.ShardUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

@Slf4j
@Service
public class SafePayBookPreApplyServiceImpl implements SafePayBookPreApplyService {

    @Autowired
    private SafePayBookPreApplyRecordManager safePayBookPreApplyRecordManager;

    @Autowired
    private PoseidonSafePayAlipayClient xpaySafePayAlipayClient;

    @Autowired
    private SafePayBookAccountManager safePayBookAccountManager;

    @Autowired
    private UserManager userManager;

    @Autowired
    private UserShardManager userShardManager;

    @Autowired
    private SafePayBusinessAuthAuditRecordManager safePayBusinessAuthAuditRecordManager;


    @Override
    public SafePayBookPreApplyRecord applySafePayBook(SafePayBookPreApplyModel applyModel) {
        if (Strings.isNullOrEmpty(applyModel.getAlipayName())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请填写企业名称");
        }
        if (Strings.isNullOrEmpty(applyModel.getAlipayNickName())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请填写企业支付宝账号");
        }
        if (!applyModel.getAlipayNickName().contains("@")) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "企业支付宝账号格式错误");
        }
        String alipayNickName = applyModel.getAlipayNickName().trim();
        String alipayName = applyModel.getAlipayName().trim();
        applyModel.setAlipayNickName(alipayNickName);
        applyModel.setAlipayName(alipayName);

        SafePayBookPreApplyRecord lastRecord = safePayBookPreApplyRecordManager.getLastByAlipayName(applyModel.getAlipayName(), applyModel.getAlipayNickName());
        if (lastRecord != null) {
            if (lastRecord.getBookStatus() == SafePayBookAccountBookStatus.YES) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "记账本已开通，请勿重复提交");
            }
//            if (lastRecord.getDeadline().isAfter(LocalDateTime.now())) {
//                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "记账本开通中，请勿重复提交");
//            }
        }

        AlipayFundAccountbookPageCreateModel model = new AlipayFundAccountbookPageCreateModel();
        String externalAgreementNo = GenIdUtil.getId(GenIdPrefixConstant.BP, 1L);
        model.setOutBizNo(externalAgreementNo);
        model.setAccountBookAlias("我的记账本");
        AlipayFundAccountbookPageCreateModel.PrincipalInfo principalInfo = new AlipayFundAccountbookPageCreateModel.PrincipalInfo();
        principalInfo.setIdentity(alipayNickName);
        principalInfo.setIdentityType(IdentityType.ALIPAY_LOGON_ID.getValue());
        principalInfo.setIdentityName(applyModel.getAlipayName());
        model.setPrincipalInfo(principalInfo);

        String authPageUrl = xpaySafePayAlipayClient.alipayFundAccountbookPageCreate(model);
        log.info("applySafePayBook alipayNickName={}|authPageUrl={}", alipayNickName, authPageUrl);
        SafePayBookPreApplyRecord record = new SafePayBookPreApplyRecord();
        record.setAlipayNickName(alipayNickName);
        record.setAlipayName(applyModel.getAlipayName());
        record.setExternalAgreementNo(externalAgreementNo);
        record.setBookStatus(SafePayBookAccountBookStatus.NO);
        record.setApplyToken(UuidUtil.uuid());
        record.setApplyUrl(authPageUrl);
        record.setDeadline(LocalDateTime.now().plusDays(3L));
        record.setMounted(false);
        safePayBookPreApplyRecordManager.save(record);

        return record;
    }

    @Override
    public void onBookCreated(String outBizNo, String agreementNo, String extCardInfo, String accountBookId) {
        SafePayBookPreApplyRecord record = safePayBookPreApplyRecordManager.getByExternalAgreementNo(outBizNo);
        if (record == null) {
            log.warn("onBookCreated error can not find account|outBizNo={}", outBizNo);
            return;
        }

        record.setAgreementNo(agreementNo);
        record.setBookId(accountBookId);
        record.setExtCardInfo(extCardInfo);
        record.setSignTime(LocalDateUtil.getDateTimeAsString(LocalDateTime.now()));
        record.setBookStatus(SafePayBookAccountBookStatus.YES);
        safePayBookPreApplyRecordManager.update(record);

        //失败重试30秒
        LocalDateTime deadline = LocalDateTime.now().plusSeconds(30L);
        long t = System.currentTimeMillis();
        while (LocalDateTime.now().isBefore(deadline)) {
            try {
                //订阅同名银行卡入金消息
                AlipayFundAccountbookNotifySubscribeResponse subscribeResponse = xpaySafePayAlipayClient.alipayFundAccountbookNotifySubscribe(record.getBookId(), record.getAgreementNo());
                if (subscribeResponse.isSuccess() && "VALID".equals(subscribeResponse.getSubscribeStatus())) {
                    log.info("onBookCreated subscribe success|cost={}|externalAgreementNo={}", System.currentTimeMillis() - t, outBizNo);
                    return;
                } else {
                    log.info("onBookCreated subscribe failed|externalAgreementNo={}", outBizNo);
                }
            } catch (AlipayApiException e) {
                log.warn("onBookCreated create book failed|externalAgreementNo={}", outBizNo, e);
            }
            ThreadUtil.safeSleep(2000L, "onBookCreated subscribe sleep");
        }

        log.info("onBookCreated subscribe final failed|externalAgreementNo={}", outBizNo);
    }


    private void mountUser(Long userId, Long id) {
        Preconditions.checkArgument(userId != null && id != null);

        User user = userManager.getById(userId);
        SafePayBookPreApplyRecord record = safePayBookPreApplyRecordManager.getById(id);
        if (!record.getAlipayName().equals(user.getName())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "挂载失败，商户名与记账本支付宝主体名称不一致");
        }

        if (record.getBookStatus() != SafePayBookAccountBookStatus.YES) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "挂载失败，记账本未开通");
        }

        if (record.getMounted()) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "记账本已被挂载");
        }

        UserShard userShard = userShardManager.getById(userId);

        try {
            ShardUtil.setShardContext(userShard.getShardId());
            SafePayBookAccount safePayBookAccount = safePayBookAccountManager.findByAlipayNickName(userId, record.getAlipayNickName());
            if (safePayBookAccount != null) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "记账本已被商户自主创建");
            }

            doMountedUser(record, user);
        } finally {
            ShardUtil.cleanShardContext();
        }

    }


    public void mountBook(Long id) {
        Preconditions.checkArgument(id != null);
        SafePayBookPreApplyRecord record = safePayBookPreApplyRecordManager.getById(id);
        User user = userManager.findByName(record.getAlipayName());
        if (user == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请先注册商户");
        }
        mountUser(user.getId(), id);
    }

    private void doMountedUser(SafePayBookPreApplyRecord record, User user) {
        SafePayBookAccount safePayBookAccount = SafePayBookAccount.getInstance();
        safePayBookAccount.setUserId(user.getId());
        safePayBookAccount.setAlipayNickName(record.getAlipayNickName());
        safePayBookAccount.setAlipayName(record.getAlipayName());
        safePayBookAccount.setExternalAgreementNo(record.getExternalAgreementNo());
        safePayBookAccount.setSignStatus(SafePayBookAccountSignStatus.NORMAL);
        safePayBookAccount.setBookStatus(record.getBookStatus());
        safePayBookAccount.setAuditStatus(SafePayBookAccountAuditStatus.INIT);
        safePayBookAccount.setSignMethod(SafePayBookAccountSignMethod.NEW);

        safePayBookAccount.setAgreementNo(record.getAgreementNo());
        safePayBookAccount.setBookId(record.getBookId());
        safePayBookAccount.setExtCardInfo(record.getExtCardInfo());
        safePayBookAccount.setSignTime(record.getSignTime());
        safePayBookAccount.setSignInvalidTime(record.getSignInvalidTime());
        safePayBookAccountManager.save(safePayBookAccount);
        //处理安全发实名认证
        doSafePayBusinessAuthAuditRecord(safePayBookAccount);

        record.setMounted(true);
        record.setMountedTime(LocalDateTime.now());
        record.setMountedUserId(user.getId());
        safePayBookPreApplyRecordManager.update(record);

    }

    private void doSafePayBusinessAuthAuditRecord(SafePayBookAccount safePayBookAccount) {

        SafePayBookAccountAuditStatus auditStatus = safePayBookAccount.getAuditStatus();
        //判断是否能修改提交信息
        if (auditStatus != SafePayBookAccountAuditStatus.INIT && auditStatus != SafePayBookAccountAuditStatus.TEMP) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "实名认证信息已提交，请勿重复提交");
        }

        SafePayBusinessAuthAuditRecord record = new SafePayBusinessAuthAuditRecord();
        record.setSafePayBookAccountId(safePayBookAccount.getId());
        record.setAlipayNickName(safePayBookAccount.getAlipayNickName());
        record.setBusinessName(safePayBookAccount.getAlipayName());
        record.setAlipayUid(safePayBookAccount.getAlipayUid());
        record.setUserId(safePayBookAccount.getUserId());
        record.setAuditStatus(SafePayBookAccountAuditStatus.INIT);
        record.setAuditSubmitTime(LocalDateTime.now());

        //如果同主体已经有审核通过的了 直接复制同主体的资质信息
        checkSetHasSameBusinessNameAuditPassRecord(record);

        safePayBusinessAuthAuditRecordManager.save(record);

    }

    private void checkSetHasSameBusinessNameAuditPassRecord(SafePayBusinessAuthAuditRecord record) {
        SafePayBusinessAuthAuditRecord selectedRecord = safePayBusinessAuthAuditRecordManager.findByBusinessName(record.getUserId(), record.getBusinessName());
        if (selectedRecord == null) {
            return;
        }

        Preconditions.checkArgument(selectedRecord.getBusinessName().equals(record.getBusinessName()));
        if (selectedRecord.getAuditStatus() == SafePayBookAccountAuditStatus.NORMAL) {
            record.setIdCardFront(selectedRecord.getIdCardFront());
            record.setBizLicense(selectedRecord.getBizLicense());
            record.setBusinessLicense(selectedRecord.getBusinessLicense());
            record.setOfficeImages(selectedRecord.getOfficeImages());

            record.setIdCardBack(selectedRecord.getIdCardBack());
            record.setIcpInfo(selectedRecord.getIcpInfo());
            record.setBizSceneDesc(selectedRecord.getBizSceneDesc());
            record.setMerchantCommitment(selectedRecord.getMerchantCommitment());

            record.setOtherOneImages(selectedRecord.getOtherOneImages());
            record.setOtherTwoImages(selectedRecord.getOtherTwoImages());
            record.setOtherThreeImages(selectedRecord.getOtherThreeImages());
        }
    }
}
